package com.example.myapplication.adapter.recycleradaper;

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;

import java.util.ArrayList;
import java.util.List;

/*
注意：payload统一使用String类型，便于控制
如果在插入数据过程中，不需要刷新布局，只需要更新索引，则调用带WithoutConvert的方法
判断：如果convert内的操作没有操作到position且对应数据没有变化，则无需重新convert
      如果convert内的操作使用到了position或相应数据发送了变化，则需要重新convert
 */
public abstract class BaseRecyclerAdapter<T, H extends RecyclerViewHelper> extends RecyclerView.Adapter<ViewHolder> {

    protected List<T> datas;
    protected Context context;
    private BaseRecyclerMultitemTypeSupport baseRecyclerMultitemTypeSupport;
    private int layoutId;
    private boolean isMultitemType;

    private ItemClickListener itemClickListener;
    private ItemLongClickListener itemLongClickListener;
    private ItemLongClickReleaseListener onItemLongClickRelease;

    private boolean isLongClick;

    public BaseRecyclerAdapter(Context context, int layoutId/*BaseRecylerViewHolder recylerViewHolderHelper*/, List<T> datas) {
        this.context = context;
        this.datas = datas == null ? new ArrayList<>() : new ArrayList<>(datas);
//        this.recylerViewHolderHelper = recylerViewHolderHelper;
        this.layoutId = layoutId;
    }

    public BaseRecyclerAdapter(Context context, List<T> datas, BaseRecyclerMultitemTypeSupport baseRecyclerMultitemTypeSupport) {
        this.context = context;
        this.datas = datas == null ? new ArrayList<>() : new ArrayList<>(datas);
        this.baseRecyclerMultitemTypeSupport = baseRecyclerMultitemTypeSupport;
        this.isMultitemType = Boolean.TRUE;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) {
        if (isMultitemType) {
            int layoutId = baseRecyclerMultitemTypeSupport.getLayoutId(type);
            View view = LayoutInflater.from(context).inflate(layoutId, viewGroup, false);
            return new ViewHolder(view) {
            };
        } else {
            View view = LayoutInflater.from(context).inflate(layoutId, viewGroup, false);
            return new ViewHolder(view) {
            };
        }
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder viewHolder, final int position) {
        boolean interrupt = onBind(viewHolder, position);
        if (interrupt)
            return;

        T t = datas.get(position);
        int itemViewType = getItemViewType(position);
        H helper = getAdapterHelper(position, viewHolder.itemView);
        convert(itemViewType, helper, t);
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder viewHolder, final int position, @NonNull List<Object> payloads) {
        if (payloads.isEmpty())
            onBindViewHolder(viewHolder, position);
        else {
            boolean interrupt = onBind(viewHolder, position);
            if (interrupt)
                return;

            T t = datas.get(position);
            int itemViewType = getItemViewType(position);
            H helper = getAdapterHelper(position, viewHolder.itemView);

            // 移除相同的payload，避免重复处理
            List<String> truePayLoads = new ArrayList<>();
            List<Object> waitDeal = new ArrayList<>();
            for (Object payload : payloads) {
                if (payload == null || truePayLoads.contains(position + payload.toString()))
                    continue;
                truePayLoads.add(position + payload.toString());
                waitDeal.add(payload);
            }
            convertPart(itemViewType, helper, t, waitDeal);
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private boolean onBind(final ViewHolder viewHolder, final int position) {
        viewHolder.itemView.setOnClickListener(v -> onItemClick(viewHolder, position));

        viewHolder.itemView.setOnLongClickListener(v -> {
            isLongClick = true;
            return onItemLongClick(viewHolder, position);
        });

        viewHolder.itemView.setOnTouchListener((view, motionEvent) -> {
            if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
                if (isLongClick && onItemLongClickRelease != null) {
                    onItemLongClickRelease.onItemLongClickRelease(view, position);
                }
                isLongClick = false;
            }
            return false;
        });

        T t = datas.get(position);
        return isMultitemType && !baseRecyclerMultitemTypeSupport.isConvert(t, position);
    }

    @Override
    public int getItemCount() {
        return datas.size();
    }

    @Override
    public int getItemViewType(int position) {
        if (position >= 0 && position < datas.size()) {
            T t = datas.get(position);
            return isMultitemType ? baseRecyclerMultitemTypeSupport.getItemViewType(t, position)
                    : super.getItemViewType(position);
        } else {
            return -1;
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    protected abstract H getAdapterHelper(int position, View itemView);

    protected abstract void convert(int viewType, RecyclerViewHelper helper, T t);

    protected void convertPart(int viewType, RecyclerViewHelper helper, T t, List<Object> payloads) {

    }

    // region 数据操作
    public void add(T elem) {
        add(datas.size(), elem);
    }

    public void add(int position, T elem) {
        if (elem != null) {
            if (position > datas.size())
                position = datas.size();
            else if (position < 0)
                position = 0;
            datas.add(position, elem);
            notifyItemInserted(position);
            if (datas.size() > position + 1) { //不刷新，索引下标会出现错误
                notifyItemRangeChanged(position + 1, datas.size() - position - 1);
            }
        }
    }

    //insert进行插入，并刷新插入位置之后的数据
    public void insertAll(List<T> elem) {
        insertAll(datas.size(), elem);
    }

    public void insertAll(int position, List<T> elem) {
        if (elem != null && !elem.isEmpty()) {
            if (position > datas.size())
                position = datas.size();
            else if (position < 0)
                position = 0;
            datas.addAll(position, elem);
            notifyItemRangeInserted(position, elem.size());
            if (datas.size() > position + elem.size()) { //不刷新，索引下标会出现错误
                notifyItemRangeChanged(position + elem.size(), datas.size() - position - elem.size());
            }
        }
    }

    public void set(T oldElem, T newElem) {
        set(datas.indexOf(oldElem), newElem);
    }

    public void set(int index, T elem) {
        datas.set(index, elem);
        notifyItemChanged(index);
    }

    public void remove(T elem) {
        if (datas != null && elem != null) {
            remove(datas.indexOf(elem));
        }
    }

    public void remove(int index) {
        if (datas != null && index >= 0 && index < datas.size()) {
            datas.remove(index);
            notifyItemRemoved(index);
            if (datas.size() - 1 >= index)
                notifyItemRangeChanged(index, datas.size() - index);
        }
    }

    public void remove(List<T> elem) {
        if (!elem.isEmpty() && !datas.isEmpty()) {
            datas.removeAll(elem);
            notifyDataSetChanged();
        }
    }

    public void removeRange(int index, int count) {
        if (datas != null && index < datas.size() && count > 0) {
            int realCount = 0;
            for (int i = index + count - 1; i >= index; i--) {
                if (i >= datas.size())
                    continue;
                datas.remove(i);
                realCount++;
            }
            notifyItemRangeRemoved(index, realCount);
            if (datas.size() - 1 >= index) {
                if (index == 0)
                    notifyDataSetChanged();
                else
                    notifyItemRangeChanged(index, datas.size() - index);
            }
        }
    }

    // 包含index
    public void removeAfter(int index) {
        if (datas != null && index < datas.size()) {
            removeRange(index, datas.size() - index);
        }
    }

    public void replaceAll(List<T> elem) {
        replaceAll(elem, 0);
    }

    /**
     * 采用数据替换形式进行界面刷新
     * 这种方式，看到的效果将是数据直接刷新替换成新的数据，可以避免数据消失之后重新显示
     *
     * @param refreshIndex 需要开始刷新的位置
     */
    public void replaceAll(List<T> elem, int refreshIndex) {
        if (datas != null) {
            int preDataSize = datas.size();
            datas.clear();
            if (elem != null && elem.size() > 0)
                datas.addAll(elem);
            if (refreshIndex == 0 || datas.size() == 0 || datas.size() <= refreshIndex) {
                notifyDataSetChanged();
            } else {
                int curDataSize = datas.size();
                if (curDataSize < preDataSize) {
                    notifyItemRangeRemoved(curDataSize, preDataSize - curDataSize);
                } else if (curDataSize > preDataSize) {
                    notifyItemRangeInserted(preDataSize, curDataSize - preDataSize);
                }
                notifyItemRangeChanged(refreshIndex, curDataSize - refreshIndex);
            }
        }
    }

    public T getItem(int position) {
        if (position >= datas.size())
            position = datas.size() - 1;
        return datas.get(position);
    }

    public List<T> getAll() {
        return datas;
    }

    public boolean contains(T elem) {
        return datas.contains(elem);
    }

    public void clear() {
        if (datas != null) {
            datas.clear();
            notifyDataSetChanged();
        }
    }
    // endregion

    // region 事件回调（点击、长按）

    /**
     * click
     */
    public interface ItemClickListener {
        void onItemClick(View itemView, int position);
    }

    /**
     * long click
     */
    public interface ItemLongClickListener {
        boolean onItemLongClick(View itemView, int position);
    }

    public interface ItemLongClickReleaseListener {
        void onItemLongClickRelease(View itemView, int position);
    }

    private void onItemClick(ViewHolder viewHolder, int position) {
        if (itemClickListener != null && position < datas.size()) {
            View view = viewHolder.itemView;
            itemClickListener.onItemClick(view, position);
        }
    }

    private boolean onItemLongClick(ViewHolder viewHolder, int position) {
        if (itemLongClickListener != null && position < datas.size()) {
            View view = viewHolder.itemView;
            return itemLongClickListener.onItemLongClick(view, position);
        }
        return false;
    }

    public void setItemClickListener(ItemClickListener clickListener) {
        this.itemClickListener = clickListener;
    }

    public void setItemLongClickListener(ItemLongClickListener longClickListener) {
        this.itemLongClickListener = longClickListener;
    }

    public void setItemLongClickReleaseListener(ItemLongClickReleaseListener longClickReleaseListener) {
        onItemLongClickRelease = longClickReleaseListener;
    }

    public ItemClickListener getItemClickListener() {
        return itemClickListener;
    }
    // endregion
}
